<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.1">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"www.lixiaofei.cn","root":"/","scheme":"Mist","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":true,"storage":true,"lazyload":true,"nav":{"valine":{"order":-1}}},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
  </script>

  <meta name="description" content="总结 技术 思考 想法">
<meta property="og:type" content="website">
<meta property="og:title" content="管窥程序">
<meta property="og:url" content="http://www.lixiaofei.cn/index.html">
<meta property="og:site_name" content="管窥程序">
<meta property="og:description" content="总结 技术 思考 想法">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="太阳雪">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="http://www.lixiaofei.cn/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : true,
    isPost : false,
    lang   : 'zh-CN'
  };
</script>

  <title>管窥程序</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">管窥程序</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">Today is a gift</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>

  <a href="https://github.com/alisx" class="github-corner" title="Follow me on GitHub" aria-label="Follow me on GitHub" rel="noopener" target="_blank"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content index posts-expand">
            
      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://www.lixiaofei.cn/2022-08-25-program-6/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.png">
      <meta itemprop="name" content="太阳雪">
      <meta itemprop="description" content="总结 技术 思考 想法">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="管窥程序">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2022-08-25-program-6/" class="post-title-link" itemprop="url">编程，真不难 6 —— 不一样的输出</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-08-25 11:22:20" itemprop="dateCreated datePublished" datetime="2022-08-25T11:22:20+08:00">2022-08-25</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-08-28 11:33:37" itemprop="dateModified" datetime="2022-08-28T11:33:37+08:00">2022-08-28</time>
              </span>

          
            <span id="/2022-08-25-program-6/" class="post-meta-item leancloud_visitors" data-flag-title="编程，真不难 6 —— 不一样的输出" title="阅读次数">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span class="leancloud-visitors-count"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/2022-08-25-program-6/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/2022-08-25-program-6/" itemprop="commentCount"></span>
    </a>
  </span>
  
  

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>在<a href="https://mp.weixin.qq.com/s/-M5sZo0lCh0P2ywwxK6Jng" target="_blank" rel="noopener">上一篇文章</a>中，我们将日志处理程序做了一定的自动化的处理，可以自动识别需要处理的日志文件，另外我们将程序做了函数化处理，将处理过程与业务理解相匹配。</p>
<p>今天我们再进一步改造，让程序可以将处理结果自动发送给相关人员，而不用我们自己手工处理。</p>
<p>这个改造不仅让我们节省了手工处理时间，更重要的是，它具备了部署服务器上，或者成为定时任务的能力，也就是说，加上这个改造之后，程序就能自理了。而让程序自理，是我们不断追求的目标。</p>
<p>现在开始吧！</p>
<h2 id="输出无所不在">输出无所不在</h2>
<p>经过前面的了解，我们知道，任何程序都是由 <strong>输入、处理、输出</strong> 三部分组成的，同时我们也了解到了一些输出的方式，比如显示在终端屏幕上、存入文件中、给其他过程提供处理后的结果等等。</p>
<p>如果将输出定义为程序向外部发送或者暴露的信息的话，那么只要是能收到的程序的反馈都可以理解为输出。</p>
<p>我们的打卡日志处理程序，最终的输出是日志分析报告，这个输出的使用者，是需要这个分析报告的相关人员，那么日志处理程序、需要日志分析报告的人员，都是日志处理过程中的一个组成部分。</p>
<p>为了更清楚地理解这个过程，我们绘制一幅图：</p>
<p><img src="../images/2022/program_7/01.png" alt="业务流程图"></p>
<p>可以看出这个过程，分为四个阶段，第一个是打卡阶段，也就是收集数据；</p>
<p>第二个是日志存储阶段，这是我们做的一个假设，即假设日志文件会被同步到文件服务器上；</p>
<p>第三个阶段就是数据处理，将日志文件处理成打卡报告；</p>
<p>第四个阶段是将报告发送给相关人员。</p>
<p>如果这么划分业务过程，我们就会发现，第一、第二两个阶段是<strong>输入</strong>，第三是<strong>处理</strong>，第四是<strong>输出</strong>，也就是说无论是一个简单的函数，还是复杂的业务流程，都可以划分为这三个部分。</p>
<p>为什么在这里再强调一遍呢？因为这样划分对于编程甚至其他事情来说都是很重要的，遇到问题首先需要将其拆解成这三个部分，然后就每个部分深入下去，整个过程就像俄罗斯套娃。</p>
<p>对于这三个部分来说，都会有千万个变化形式，和不同表现方式，比如输入，可以是通过键盘输入，也可以是通过文件输入，甚至通过光线、声音、图像等等，一切都可以是输入。</p>
<h2 id="上古神器-——-邮件">上古神器 —— 邮件</h2>
<p>邮件想必大家都不陌生，她可是先于互联网大规模发展之前，就风生水起的神器，将世界各地的人连接了起来，虽然现在邮件的影响力不如以前，但在我们的日常生活中还是具有重要作用的。</p>
<p>我们用邮件作为通知方式很合适，首先在企业内部邮件几乎是标配，发信息，发通知几乎全靠她；另外，邮件比较容易配置，程序操作更方便；最后，邮件几乎免费，只要设置好配置，就能畅通无阻。</p>
<blockquote>
<p>当然并不是能为所欲为，各大邮件服务商加大了违规力度，另外基于 AI 的反垃圾邮件机制已经很强大了;）</p>
</blockquote>
<p>Python 提供了专门用于发邮件的库，可以像一个邮件客户端一样收发邮件。我们先看一段代码：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> smtplib</span><br><span class="line"><span class="keyword">from</span> email.mime.multipart <span class="keyword">import</span> MIMEMultipart</span><br><span class="line"><span class="keyword">from</span> email.mime.text <span class="keyword">import</span> MIMEText</span><br><span class="line"></span><br><span class="line">msg = MIMEMultipart(<span class="string">'alternative'</span>)  <span class="comment"># 实例化email对象</span></span><br><span class="line"></span><br><span class="line">msg.attach(MIMEText(<span class="string">'Hello World!'</span>, <span class="string">'html'</span>))</span><br><span class="line"></span><br><span class="line"><span class="keyword">with</span> smtplib.SMTP_SSL(<span class="string">'smtp.163.com'</span>, <span class="number">465</span>) <span class="keyword">as</span> smtp:</span><br><span class="line">    smtp.ehlo()  <span class="comment"># 用户认证</span></span><br><span class="line">    smtp.login(<span class="string">'xiaofeilife'</span>, <span class="string">'AJLSKQWYKXXWOFOA'</span>)  <span class="comment"># 括号中对应的是发件人邮箱账号、邮箱密码</span></span><br><span class="line">    smtp.sendmail(<span class="string">'xiaofeilife@163.com'</span>, <span class="string">'xiaofeilife@163.com'</span>, str(msg))  <span class="comment"># 收件人邮箱账号、发送邮件</span></span><br></pre></td></tr></table></figure>
<p>是否感觉有些复杂，其实仔细看看，没有循环也没有判断，只是顺序执行，说明一下就懂了。</p>
<blockquote>
<p>这里插一句: 凡是有用的，质量好的模块内部代码都比较复杂，就像一个打开表壳的机械表一样，但不用怕，我们只需要利用它精确的输出就好，暂时不必掉入细节的坑里。</p>
</blockquote>
<ul>
<li>首先需要引入邮件发送库，<code>smtplib</code> 是发送客户端，剩下两个是主要是用于邮件内容格式化的</li>
<li>然后创建一个邮件内容对象，写法是固定的，主要是因为手工书写邮件内容很麻烦，因为内容不仅只包含邮件内容，可以用 <code>print(msg)</code> 将内容打印出来观察一下</li>
<li>接着将邮件内容格式化成 html 格式，附加在邮件内容对上</li>
<li>创建邮件发送对象，注意这里的两个参数，分别是邮件发送服务器的网址，和端口号，服务器网址可以在邮件服务器设置中找到，不同邮件服务器的配置大同小异，端口的话一般都是加密发送，所以默认是 <code>465</code></li>
<li>开启用户认证: <code>ehlo()</code>，然后提供用户名密码登录: <code>login</code></li>
<li>最后提供发件人、收件人邮箱地址 和 邮件内容，发送邮件</li>
<li>注意 <code>with</code> 它帮助我们免去了 <code>close</code> 的调用，如果不使用 <code>with</code> 记得完事后调用 <code>close</code> 或 <code>quit</code> 方法</li>
</ul>
<blockquote>
<p>笔者在 163 邮箱中测试通过，如果读者想要测试的话，可以注册一个网易邮箱试试，需要在邮件设置中开启 IMAP/SMTP服务</p>
</blockquote>
<p>这是执行后收到的测试邮件：</p>
<p><img src="../images/2022/program_7/02.png" alt="测试邮件"></p>
<p>通过分析代码我们会看到，发送邮件的代码中，除了几处需要特殊内容之外，整个过程大体都是固定的。</p>
<p>想到什么了吗？</p>
<p>如果是固定的，也就是我们下一次再遇到发送邮件的需求时，可以复制过去直接用。</p>
<p>Bingo！</p>
<p>有没有更好的复制办法呢？比如，代码好找，复制内容少，且不易出错。</p>
<p>当然有，那就是 —— <strong>类</strong></p>
<h2 id="专业功能提供者-——-类">专业功能提供者 —— 类</h2>
<p>头一次听 <strong>类</strong> 这个词会觉得很难理解，不知所云。放心吧，有这样感觉的人不在少数。</p>
<p>主要是，<strong>类</strong> 在英语中是 <code>class</code> 这个词，直接翻译过来就成了 <strong>类</strong>，实际上称之为 类型 可能更为合适，不是类型早已被占用，又加上 <code>类</code> 无处不在，所以就叫 <code>类</code> 了。</p>
<p>那么什么是 <code>类</code> 呢？</p>
<p>要理解其实很简单，想一下我们之前的编程练习，就能体会到 <strong>程序是对数据处理加工的过程</strong>，更进一步，程序是由 <strong>代码</strong>（程序处理逻辑）和 <strong>数据</strong> 组成的。</p>
<p>比如我们前面，解决日志文件最后处理的日志文件名问题时，将文件名写入了配置文件，那么配置文件就是数据，而读写配置文件的方法就是处理逻辑。</p>
<p>那么 <strong>类就是: 将处理逻辑和数据组合打包在一起的东西</strong>。</p>
<p>可能还不好理解，举个例子，一个维修工，来家里修电器，我们只需要将坏掉的电器给他，一会儿他给我们修理好的电器。</p>
<p>修理过程中不需要我们提供给他工具，也不需要我们在修理之后做清扫，他会自主完成所有任务，并清理垃圾，比如剥落的电线、使用的工具、换掉的器件等等。</p>
<p>类就像程序中的专业维修员，我们只需要给类提供必要的参数，程序就能被反复的使用，不用考虑其他东西，而且程序内部再复杂，处理输出，也不会对外部产生影响。</p>
<p>因此我们可以说类是程序中的专业功能提供者，相当于类承担了功能与数据处理的双重特性。</p>
<h3 id="类的构造">类的构造</h3>
<p>如何构造一个类呢？看代码：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyClass</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, name)</span>:</span></span><br><span class="line">        self.name = name</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">sayHello</span><span class="params">(self)</span>:</span></span><br><span class="line">        print(self.name, <span class="string">': Hello world'</span>)</span><br></pre></td></tr></table></figure>
<p>这就完成了一个类的构造，我们来仔细看看：</p>
<ul>
<li>通过关键字 <code>class</code> 引导一个类的定义，并命名类为 <code>MyClass</code>, 这一点和函数的定义类似</li>
<li>在内部，定义了一个方法 <code>__init__</code>，注意，必须这么命名，因为这个方法具有特殊的作用，即在类构建成对象（实例化过程，随后详述）的时候，对对象进行一定初始化的方法，比如这里，将一个名字初始化到对象中</li>
<li><code>sayHello</code> 是一个普通函数，用来打印一句问候语</li>
</ul>
<p>需要特别注意 <code>self</code> 参数，无论是在初始化方法上，还是自定义的普通方法上，都是第一个参数，什么作用呢？这个 <code>self</code> 指的是类或者实例化之后的对象本身。</p>
<p>举个例子，就相当于专业维修工需要一个工具时，不用问别人要，直接从自己身上带的工具包里找就好了，这个 <strong>自己本身</strong> ，就是 <code>self</code>。</p>
<p>因为在类中，当需要用到类本身时，需要有个地方能取到，所以 Python 中引入了 <code>self</code> 这个关键字，在其他面向对象语言中，也有类似的概念，比如 <a href="http://c.biancheng.net/view/953.html" target="_blank" rel="noopener" title="Java this">Java</a> 中的 <code>this</code>。</p>
<p>再看一下 <code>sayHello</code> 方法，在 <code>print</code> 时，先用了  <code>self.name</code>，这就是从对象本身中获取 <code>name</code> 属性的方式。</p>
<p>既然能这样获取属性，那么能获取方法吗？答案是肯定的。</p>
<h3 id="类的实例化">类的实例化</h3>
<p>读者可能有种感觉，定义类和定义一个变量没太大区别。是的，在写法上没有太大区别，但是在含义上有巨大的差异。</p>
<p>定义变量后，就可以直接赋值或者操作了，也就是说，操作系统已经帮我们在内存中申请了存储空间了。</p>
<p>但是类不是的，定义好了类，相当于给程序新添加了一种变量类型，类似于 <code>int</code>、<code>str</code> 等一样，如果要使用，必须将其实例化成一个变量（对象），例如：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">hello = MyClass(<span class="string">'Python Class'</span>) <span class="comment"># 实例化一个对象</span></span><br><span class="line"></span><br><span class="line">hello.sayHello() <span class="comment"># Python Class : Hello world!</span></span><br></pre></td></tr></table></figure>
<p>第一行就是实例化一个对象，注意这里的定义相当于把 <code>MyClass</code> 看作方法，而参数，就是 <code>__init__</code> 初始化方法的参数，注意，不用附带 <code>self</code> 这个参数，Python 编译机制会为我们处理好的。</p>
<p>这样就定义了一个 <code>hello</code> 变量，或者说将 MyClass <strong>实例化</strong> 成为一个对象了。</p>
<p>一般来说，一个类可以被实例化成无数个对象，除非为了实现一些特殊的功能，比如<a href="https://www.runoob.com/design-pattern/singleton-pattern.html" target="_blank" rel="noopener" title="单例模式">单例模式</a>中，类可能只能被实例化一次。</p>
<p>实例化好的对象，就可以像一般变量一样用，注意，在调用 <code>sayHello</code> 方法时，我们并没有传递过任何参数，但可以打印出实例化时，赋予的参数值，这就是类中 <code>self</code> 的作用的体现。</p>
<h2 id="邮件类">邮件类</h2>
<p>了解了 Python 中的类，我们再回到发送邮件时留的那个问题上，如何让复制代码变得更简单。</p>
<p>答案是，将其编写成邮件类。</p>
<p>读者可以会说了，为什么不编写成一个函数呢？</p>
<p>其实也不是不可以，不过如果是类的话，就能为我们附带一些处理工具，而不必每次都创建了，比如一些配置信息，可以初始化到类中，不必每次都写一个很长的参数。</p>
<p>当然了解了类之后，还可以做更多的事情，因为我们主要是要快速习得编程技能嘛。</p>
<p>分析前面的代码，发送邮件分为两部分，一部分是配置信息，另一部分是发送处理过程。</p>
<p>配置信息中，我们需要提供邮件服务器地址，端口，用户名，密码等，这部分可以在初始化时完成。</p>
<p>发送处理过程主要是邮件的内容，这部分每次可能不同，我们通过方法的参数提供。</p>
<p>好了，直接看一下实例代码：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> smtplib</span><br><span class="line"><span class="keyword">from</span> email.mime.multipart <span class="keyword">import</span> MIMEMultipart</span><br><span class="line"><span class="keyword">from</span> email.mime.text <span class="keyword">import</span> MIMEText</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MailSent</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, **config)</span>:</span></span><br><span class="line">        self.config = &#123;</span><br><span class="line">            <span class="string">'FROM'</span>: config.get(<span class="string">'mail_from'</span>, <span class="string">'&lt;换成默认的发送邮件地址&gt;'</span>),</span><br><span class="line">            <span class="string">'HOST'</span>: config.get(<span class="string">'mail_host'</span>, <span class="string">'smtp.company.com'</span>),</span><br><span class="line">            <span class="string">'PORT'</span>: config.get(<span class="string">'port'</span>, <span class="number">465</span>),</span><br><span class="line">            <span class="string">'USER'</span>: config.get(<span class="string">'user'</span>, <span class="string">'&lt;换成默认的用户名&gt;'</span>),</span><br><span class="line">            <span class="string">'PASS'</span>: config.get(<span class="string">'password'</span>, <span class="string">'&lt;换成默认的密码&gt;'</span>),</span><br><span class="line">            <span class="string">'SSL'</span>: config.get(<span class="string">'ssl'</span>, <span class="literal">True</span>),</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">send_mail</span><span class="params">(self, to_mails, title, content)</span>:</span></span><br><span class="line">        ret = <span class="literal">True</span></span><br><span class="line">        FROM_MAIL = self.config[<span class="string">'FROM'</span>]  <span class="comment"># 发件人</span></span><br><span class="line">        TO_MAIL = to_mails.split(<span class="string">','</span>) <span class="comment"># 收件人</span></span><br><span class="line">        SMTP_SERVER = self.config[<span class="string">'HOST'</span>]  <span class="comment"># qq邮箱服务器</span></span><br><span class="line">        SSL_PORT = self.config[<span class="string">'PORT'</span>]  <span class="comment"># 加密端口</span></span><br><span class="line">        USER_NAME = self.config[<span class="string">'USER'</span>]  <span class="comment"># qq邮箱用户名</span></span><br><span class="line">        USER_PWD = self.config[<span class="string">'PASS'</span>]  <span class="comment"># qq邮箱授权码</span></span><br><span class="line"></span><br><span class="line">        msg = MIMEMultipart(<span class="string">'alternative'</span>)  <span class="comment"># 实例化email对象</span></span><br><span class="line">        msg[<span class="string">'from'</span>] = FROM_MAIL  <span class="comment"># 对应发件人邮箱昵称、发件人邮箱账号</span></span><br><span class="line">        msg[<span class="string">'to'</span>] = <span class="string">';'</span>.join(TO_MAIL)  <span class="comment"># 对应收件人邮箱昵称、收件人邮箱账号</span></span><br><span class="line">        msg[<span class="string">'subject'</span>] = title  <span class="comment"># 邮件的主题</span></span><br><span class="line">        txt = MIMEText(content, <span class="string">'html'</span>)</span><br><span class="line">        msg.attach(txt)</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 纯粹的ssl加密方式</span></span><br><span class="line">        <span class="keyword">with</span> smtplib.SMTP_SSL(SMTP_SERVER, SSL_PORT) <span class="keyword">as</span> smtp:  <span class="comment"># 邮件服务器地址和端口</span></span><br><span class="line">            smtp.ehlo()  <span class="comment"># 用户认证</span></span><br><span class="line">            smtp.login(USER_NAME, USER_PWD)  <span class="comment"># 括号中对应的是发件人邮箱账号、邮箱密码</span></span><br><span class="line">            smtp.sendmail(FROM_MAIL, TO_MAIL, str(msg))  <span class="comment"># 收件人邮箱账号、发送邮件</span></span><br></pre></td></tr></table></figure>
<p>不用被这么大篇幅吓到，仔细看，其实很简单的。</p>
<p>第一部分，是库的引用，不必多说。</p>
<p>第二部分是邮件类的定义，我们稍作分析。</p>
<p>仔细观察，不难发现，和我们的类定义示例代码没有本质区别，还是有 <code>__init__</code> 和一个自定方法构成。</p>
<p>初始化方法中，将所有的配置都记录在类自身的 <code>config</code> 词典上了，值得注意的是初始化参数 <code>**config</code>。</p>
<blockquote>
<p>参数前面加两个星号是什么意思呢？</p>
<p>我们在写函数参数时，对每个参数都做了命名，被称作为 <strong>形参</strong>，当提供参数时，我们可以在参数对应的位置上，提供实参值，但有些时候，我们需要向函数提供许多参数，而且可能不确定数量，就可以用加两个星号的 <strong>展开形式</strong> 提供参数。</p>
<p>调用起来很正常定义的方法一样，不过参数数量、名称可以随意（当然需要函数内部知道才行），最重要的是顺序也可以随意，所以在定义时并没有强调参数的顺序。</p>
<p>比如 <code>MailSent(mail_from='from@mail.com', mail_to='to@mail.com')</code> 和<br>
<code>MailSent(mail_to='to@mail.com'，mail_from='from@mail.com')</code> 效果是一样的。</p>
</blockquote>
<p>另外在自定义方法 <code>send_mail</code>，对 <code>to_mails</code> 参数做了处理，如果需要给多个人发送的话，可以用逗号分隔，和在邮件客户端中的方式一样，所以需要对 <code>to_mails</code> 参数进行处理，用逗号拆分成数组。</p>
<h2 id="替换通知方式">替换通知方式</h2>
<p>现在终于可以进入业务改造了，将通知方式替换成邮件通知形式。</p>
<p>上篇文章中，讨论的集成中的打印报告部分进行改造，传送门：《<a href="https://mp.weixin.qq.com/s/-M5sZo0lCh0P2ywwxK6Jng" target="_blank" rel="noopener">需求变了</a>》。</p>
<p>为此我们编写一个通知函数: <code>notify</code>：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mail = MailSent(mail_from= <span class="string">'from@company.com'</span>, user=<span class="string">'from'</span>, password=<span class="string">'*****'</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">notify</span><span class="params">(tomails, report)</span>:</span></span><br><span class="line">    mail.send_mail(tomails, <span class="string">'打卡日志报告'</span>, report)</span><br></pre></td></tr></table></figure>
<p>与之前相比，多了邮件对象定义，本质上和 <code>print</code> 没有区别，而效果是将通过用邮件的方式发送出去。</p>
<p>假如我们需要给三个管理者发送邮件，他们的邮箱地址分别是 <code>manager_a@company.com</code>、<code>manager_b@company.com</code>、<code>manager_c@company.com</code>。</p>
<p>将其集成到业务主干代码中：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">configfile = <span class="string">'config.txt'</span></span><br><span class="line">logdir = <span class="string">'log'</span></span><br><span class="line">tomails = <span class="string">'manager_a@company.com, manager_b@company.com, manager_c@company.com'</span></span><br><span class="line">targetFilename = findTargetFileName(configfile, logdir)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> targetFilename:</span><br><span class="line">    report = genReport(targetFilename)</span><br><span class="line">    notify(tomails, report) <span class="comment"># 这里替换了print</span></span><br><span class="line">    setConf(configfile, targetFilename)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">    print(<span class="string">'没有需要处理的文件'</span>)</span><br></pre></td></tr></table></figure>
<p>这样改造工作就完成了，除了对发送邮件类的编写需要费较大的精力，而中主要的部分，竟然只需要改一行代码。</p>
<p>这是因为我们前面对整体代码做了梳理，将其做了函数化转化，而让后期的改造工作变得更加丝滑。</p>
<p>需要注意的是，什么的示例代码中，使用的邮件地址都是编造的，在实际当中需要替换成实际的邮件地址，否则可能发送不成功。</p>
<h2 id="总结">总结</h2>
<p>今天我们从日志报告输出的角度上，对日志处理程序做了改进，主要是要理解程序的三个组成部分：<code>输入</code>，<code>输出</code> 和 <code>处理</code>，每个部分都可以有不同的变体，但本质是不变的。</p>
<p>然后我们通过实现发送邮件，引入了 <code>类</code> 的概念，对于 <code>类</code> 来说，是<a href="https://baike.baidu.com/item/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1" target="_blank" rel="noopener" title="面向对象编程">面向对象编程</a>的核心元素，理解和掌握需要大量的理论和实践练习，我们这里只是做了简单的感性说明，让读者知道有类存在，以及能做什么。在实践中，不会感到困惑，并增加一种代码封装的方法，关于更多面向对象的知识，还需要系统学习面向对象的编程的理论。</p>
<p>另外，我们通过实现最初的设想讨论了，有关程序改造的话题，在实际项目当中，改造或者变更是最让人痛苦的话题，往往会牵一发而动全身，以至于程序员们潜意识里就惧怕改动。</p>
<p>就像上篇文章中我们讨论的一样，程序无法改造或者改造困难，往往是人祸大于天灾，常常是不严守开发质量，对坏代码置之不理，而导致的必然结果。</p>
<p>因此我们在从开始的时候，就需要对代码的质量严加把控，提升灵活性，做组件和函数化改造。</p>
<p>话说，今天我们的实现中，也有些坏代码的味道，你发现了吗？</p>
<p>就是收件人邮件列表，我们用了死代码的方式实现的，虽然在短期可能不会有影响，但是长期来看，领导者可能更换，发送形式可能有变化（比如，不同的管理者需要的报告形式不不同等），都会对代码造成冲击，所以在上线以前，最好将这里调整过来。</p>
<p>怎么调整呢？提示一下 —— 配置文件 是个好方法。至于如何实现，需要读者自己想办法练习解决。</p>
<p>最后还一个地方值得修缮，就是通知邮件的格式，我们默认使用了打印在终端上的格式，但邮件中应该有称呼，有落款等个性化的信息，如何处理呢？读者可以开动脑筋思考一下。</p>
<p>好的今天的内容就到这里结束，笔者的水平有限，文章中难免出现各种错误和问题，恳请读者不吝批评、指正。十分感谢！</p>
<p>比心！</p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://www.lixiaofei.cn/2022-07-12-program-5/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.png">
      <meta itemprop="name" content="太阳雪">
      <meta itemprop="description" content="总结 技术 思考 想法">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="管窥程序">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2022-07-12-program-5/" class="post-title-link" itemprop="url">编程，真不难 6 —— 需求变了</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-07-12 06:15:06" itemprop="dateCreated datePublished" datetime="2022-07-12T06:15:06+08:00">2022-07-12</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-08-26 10:45:35" itemprop="dateModified" datetime="2022-08-26T10:45:35+08:00">2022-08-26</time>
              </span>

          
            <span id="/2022-07-12-program-5/" class="post-meta-item leancloud_visitors" data-flag-title="编程，真不难 6 —— 需求变了" title="阅读次数">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span class="leancloud-visitors-count"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/2022-07-12-program-5/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/2022-07-12-program-5/" itemprop="commentCount"></span>
    </a>
  </span>
  
  

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p><a href="https://mp.weixin.qq.com/s/DAzqzcJd3BiwNgmL9ajrsw" target="_blank" rel="noopener">上篇文章</a>中，我们通过一个例子，了解了如何从文本文件中读取数据，并做统计处理，简单的一个脚本能帮助我们解脱繁琐的工作，将宝贵的时间用在更重要的事情上。</p>
<p>作为练习还行，但作为真正有用的程序还有很大的差距，今天我们就来再进一步，让程序更智能更有用。</p>
<p>然后我们需要了解一种程序设计思维，这种思维方式，可以帮我们解决很多需求分析问题。</p>
<p>现在开始吧！</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2022-07-12-program-5/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://www.lixiaofei.cn/2022-06-27-program-4/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.png">
      <meta itemprop="name" content="太阳雪">
      <meta itemprop="description" content="总结 技术 思考 想法">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="管窥程序">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2022-06-27-program-4/" class="post-title-link" itemprop="url">编程，真不难 5 —— 初出茅庐</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-06-27 06:37:40" itemprop="dateCreated datePublished" datetime="2022-06-27T06:37:40+08:00">2022-06-27</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-07-01 14:02:41" itemprop="dateModified" datetime="2022-07-01T14:02:41+08:00">2022-07-01</time>
              </span>

          
            <span id="/2022-06-27-program-4/" class="post-meta-item leancloud_visitors" data-flag-title="编程，真不难 5 —— 初出茅庐" title="阅读次数">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span class="leancloud-visitors-count"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/2022-06-27-program-4/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/2022-06-27-program-4/" itemprop="commentCount"></span>
    </a>
  </span>
  
  

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>上一篇文章 《<a href="https://mp.weixin.qq.com/s/efoHrlY0fa1NXPhZDOXcJg" target="_blank" rel="noopener">流程控制</a>》中，我们了解了如何控制程序流程，使用的是 <strong>顺序</strong>、<strong>分支</strong> 和 <strong>循环</strong>，三个结构。</p>
<p>理论上，任何编程语言，了解了流程控制方法，就已经是入门了，而后面的主要是学习和掌握编程一些语言的特性。</p>
<p>今天，我们就利用已经掌握的编程技能，解决一个实际问题，怎么样，有信心吗？</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2022-06-27-program-4/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://www.lixiaofei.cn/2022-06-09-program-3/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.png">
      <meta itemprop="name" content="太阳雪">
      <meta itemprop="description" content="总结 技术 思考 想法">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="管窥程序">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2022-06-09-program-3/" class="post-title-link" itemprop="url">编程，真不难 —— 流程控制</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-06-09 06:35:17" itemprop="dateCreated datePublished" datetime="2022-06-09T06:35:17+08:00">2022-06-09</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-06-15 07:53:19" itemprop="dateModified" datetime="2022-06-15T07:53:19+08:00">2022-06-15</time>
              </span>

          
            <span id="/2022-06-09-program-3/" class="post-meta-item leancloud_visitors" data-flag-title="编程，真不难 —— 流程控制" title="阅读次数">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span class="leancloud-visitors-count"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/2022-06-09-program-3/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/2022-06-09-program-3/" itemprop="commentCount"></span>
    </a>
  </span>
  
  

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>在上篇 《<a href="https://mp.weixin.qq.com/s/8iyrWHThg0P8IojStSE2sQ" target="_blank" rel="noopener">基础语法</a>》中，我们了解到，编程语言由 <strong>语法</strong> 和 <strong>流程控制</strong> 组成。</p>
<p>了解了基础语法之后，我们就能大体看懂代码的结构，如果要实践的话，还需要知道如何控制程序的流程。</p>
<p>今天我们将会了解：三个流程控制单元，以及如何进行流程可视化。</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2022-06-09-program-3/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://www.lixiaofei.cn/2022-06-04-program-2/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.png">
      <meta itemprop="name" content="太阳雪">
      <meta itemprop="description" content="总结 技术 思考 想法">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="管窥程序">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2022-06-04-program-2/" class="post-title-link" itemprop="url">编程，真不难 3 —— 基础语法</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-06-04 08:44:44" itemprop="dateCreated datePublished" datetime="2022-06-04T08:44:44+08:00">2022-06-04</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-06-09 12:42:36" itemprop="dateModified" datetime="2022-06-09T12:42:36+08:00">2022-06-09</time>
              </span>

          
            <span id="/2022-06-04-program-2/" class="post-meta-item leancloud_visitors" data-flag-title="编程，真不难 3 —— 基础语法" title="阅读次数">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span class="leancloud-visitors-count"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/2022-06-04-program-2/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/2022-06-04-program-2/" itemprop="commentCount"></span>
    </a>
  </span>
  
  

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>上篇文章《<a href="https://mp.weixin.qq.com/s/8iyrWHThg0P8IojStSE2sQ" target="_blank" rel="noopener">编程环境</a>》中，我们了解了如何搭建一个 Python 的编程环境。</p>
<p>有了编程环境之后，理论上就能实现任何想要的程序了。</p>
<p>如《<a href="https://book.douban.com/subject/1152971/" target="_blank" rel="noopener">DOOM 启世录</a>》中所说：</p>
<blockquote>
<p>如果你想动手开发什么全新的技术，你不需要几百万美元的资金，你只需要在冰箱里放满比萨和可乐，再有一台便宜的计算机，和为之献身的决心。</p>
</blockquote>
<p>Python 编译器，就是我们的计算机，是我们征战星辰大海的装备。</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2022-06-04-program-2/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://www.lixiaofei.cn/2022-05-29-program-1/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.png">
      <meta itemprop="name" content="太阳雪">
      <meta itemprop="description" content="总结 技术 思考 想法">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="管窥程序">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2022-05-29-program-1/" class="post-title-link" itemprop="url">编程，真不难 2 —— 编程环境</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-05-29 06:59:14" itemprop="dateCreated datePublished" datetime="2022-05-29T06:59:14+08:00">2022-05-29</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-05-30 15:13:40" itemprop="dateModified" datetime="2022-05-30T15:13:40+08:00">2022-05-30</time>
              </span>

          
            <span id="/2022-05-29-program-1/" class="post-meta-item leancloud_visitors" data-flag-title="编程，真不难 2 —— 编程环境" title="阅读次数">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span class="leancloud-visitors-count"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/2022-05-29-program-1/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/2022-05-29-program-1/" itemprop="commentCount"></span>
    </a>
  </span>
  
  

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>在《编程，真不难》中，我们对编程做了初步认识，并选择 Python 作为默认的编程语言。</p>
<p>下面，就来看看如何用 Python 编程，用程序员的说法就是让程序 <strong>跑起来</strong>。</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2022-05-29-program-1/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://www.lixiaofei.cn/2022-05-27-program-0/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.png">
      <meta itemprop="name" content="太阳雪">
      <meta itemprop="description" content="总结 技术 思考 想法">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="管窥程序">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2022-05-27-program-0/" class="post-title-link" itemprop="url">编程，并没有想象的那么难</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-05-27 08:37:29" itemprop="dateCreated datePublished" datetime="2022-05-27T08:37:29+08:00">2022-05-27</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-05-28 07:21:04" itemprop="dateModified" datetime="2022-05-28T07:21:04+08:00">2022-05-28</time>
              </span>

          
            <span id="/2022-05-27-program-0/" class="post-meta-item leancloud_visitors" data-flag-title="编程，并没有想象的那么难" title="阅读次数">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span class="leancloud-visitors-count"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/2022-05-27-program-0/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/2022-05-27-program-0/" itemprop="commentCount"></span>
    </a>
  </span>
  
  

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>编程，已不再是陌生的技能了。但对很多人来说，还是遥不可及。</p>
<p>很多时候，我们渴望掌握编程技能，但往往因为一些对编程的认识，以及实践中遇到的问题，比如不知道如何开始、没有一个合适的引导等，不得不放弃。</p>
<p>下面，我就从对编程的理解、可能存在的困扰等方面，做一个简单阐述，期望能在编程技能上，助你一臂之力。</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2022-05-27-program-0/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://www.lixiaofei.cn/2022-02-15-python-tech-articles/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.png">
      <meta itemprop="name" content="太阳雪">
      <meta itemprop="description" content="总结 技术 思考 想法">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="管窥程序">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2022-02-15-python-tech-articles/" class="post-title-link" itemprop="url">在 Python 技术公号上写的文章整理</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              

              <time title="创建时间：2022-02-15 17:56:06 / 修改时间：17:59:46" itemprop="dateCreated datePublished" datetime="2022-02-15T17:56:06+08:00">2022-02-15</time>
            </span>

          
            <span id="/2022-02-15-python-tech-articles/" class="post-meta-item leancloud_visitors" data-flag-title="在 Python 技术公号上写的文章整理" title="阅读次数">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span class="leancloud-visitors-count"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/2022-02-15-python-tech-articles/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/2022-02-15-python-tech-articles/" itemprop="commentCount"></span>
    </a>
  </span>
  
  

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>在 Python 技术 公号上 发表的文章，以发表时间从前到后排列。</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2022-02-15-python-tech-articles/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://www.lixiaofei.cn/2022-02-14-2021-summary-write/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.png">
      <meta itemprop="name" content="太阳雪">
      <meta itemprop="description" content="总结 技术 思考 想法">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="管窥程序">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2022-02-14-2021-summary-write/" class="post-title-link" itemprop="url">2021 年终总结 —— 写作篇</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-02-14 22:01:46" itemprop="dateCreated datePublished" datetime="2022-02-14T22:01:46+08:00">2022-02-14</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-03-31 17:29:44" itemprop="dateModified" datetime="2022-03-31T17:29:44+08:00">2022-03-31</time>
              </span>

          
            <span id="/2022-02-14-2021-summary-write/" class="post-meta-item leancloud_visitors" data-flag-title="2021 年终总结 —— 写作篇" title="阅读次数">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span class="leancloud-visitors-count"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/2022-02-14-2021-summary-write/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/2022-02-14-2021-summary-write/" itemprop="commentCount"></span>
    </a>
  </span>
  
  

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>一转眼 2021 年已经过去一个多月了，现在应该梳理一下过去的一年，看看自己做了什么，有啥长进，有啥问题，以便更了解自己，对未来的一年有所指导。</p>
<p>这一篇是对过去写作的梳理。</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2022-02-14-2021-summary-write/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://www.lixiaofei.cn/2022-02-11-2021-summary-read/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.png">
      <meta itemprop="name" content="太阳雪">
      <meta itemprop="description" content="总结 技术 思考 想法">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="管窥程序">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/2022-02-11-2021-summary-read/" class="post-title-link" itemprop="url">2021 年终总结 —— 读书篇</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-02-11 19:15:33" itemprop="dateCreated datePublished" datetime="2022-02-11T19:15:33+08:00">2022-02-11</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-02-14 22:00:31" itemprop="dateModified" datetime="2022-02-14T22:00:31+08:00">2022-02-14</time>
              </span>

          
            <span id="/2022-02-11-2021-summary-read/" class="post-meta-item leancloud_visitors" data-flag-title="2021 年终总结 —— 读书篇" title="阅读次数">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span class="leancloud-visitors-count"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/2022-02-11-2021-summary-read/#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/2022-02-11-2021-summary-read/" itemprop="commentCount"></span>
    </a>
  </span>
  
  

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>一转眼 2021 年已经过去一个多月了，现在应该梳理一下过去的一年，看看自己做了什么，有啥长进，有啥问题，以便更了解自己，对未来的一年有所指导。</p>
<p>这一篇是去年读过的书的梳理。</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/2022-02-11-2021-summary-read/#more" rel="contents">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  


  
  <nav class="pagination">
    <span class="page-number current">1</span><a class="page-number" href="/page/2/">2</a><span class="space">&hellip;</span><a class="page-number" href="/page/9/">9</a><a class="extend next" rel="next" href="/page/2/"><i class="fa fa-angle-right" aria-label="下一页"></i></a>
  </nav>



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="太阳雪"
      src="/images/avatar.png">
  <p class="site-author-name" itemprop="name">太阳雪</p>
  <div class="site-description" itemprop="description">总结 技术 思考 想法</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">88</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">14</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">47</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">太阳雪</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://mist.theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Mist</a> 强力驱动
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/muse.js"></script>


<script src="/js/next-boot.js"></script>




  
  <script>
    (function(){
      var canonicalURL, curProtocol;
      //Get the <link> tag
      var x=document.getElementsByTagName("link");
		//Find the last canonical URL
		if(x.length > 0){
			for (i=0;i<x.length;i++){
				if(x[i].rel.toLowerCase() == 'canonical' && x[i].href){
					canonicalURL=x[i].href;
				}
			}
		}
    //Get protocol
	    if (!canonicalURL){
	    	curProtocol = window.location.protocol.split(':')[0];
	    }
	    else{
	    	curProtocol = canonicalURL.split(':')[0];
	    }
      //Get current URL if the canonical URL does not exist
	    if (!canonicalURL) canonicalURL = window.location.href;
	    //Assign script content. Replace current URL with the canonical URL
      !function(){var e=/([http|https]:\/\/[a-zA-Z0-9\_\.]+\.baidu\.com)/gi,r=canonicalURL,t=document.referrer;if(!e.test(r)){var n=(String(curProtocol).toLowerCase() === 'https')?"https://sp0.baidu.com/9_Q4simg2RQJ8t7jm9iCKT-xh_/s.gif":"//api.share.baidu.com/s.gif";t?(n+="?r="+encodeURIComponent(document.referrer),r&&(n+="&l="+r)):r&&(n+="?l="+r);var i=new Image;i.src=n}}(window);})();
  </script>















  

  


<script>
NexT.utils.loadComments(document.querySelector('#valine-comments'), () => {
  NexT.utils.getScript('//unpkg.com/valine/dist/Valine.min.js', () => {
    var GUEST = ['nick', 'mail', 'link'];
    var guest = 'nick,mail';
    guest = guest.split(',').filter(item => {
      return GUEST.includes(item);
    });
    new Valine({
      el         : '#valine-comments',
      verify     : false,
      notify     : false,
      appId      : 'teRj7yeJj0xpfGKLJ5uFdbIu-gzGzoHsz',
      appKey     : '3uie0p1nxouCCnkjiXTEBeLd',
      placeholder: "您的关注是我的动力",
      avatar     : 'mm',
      meta       : guest,
      pageSize   : '10' || 10,
      visitor    : true,
      lang       : 'zh-cn' || 'zh-cn',
      path       : location.pathname,
      recordIP   : false,
      serverURLs : ''
    });
  }, window.Valine);
});
</script>

</body>
</html>
